package com.ceam.biz.activiti.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ceam.biz.activiti.consts.ActivitiConstant;
import com.ceam.biz.activiti.dto.ProcessDto;
import com.ceam.biz.activiti.entity.BizBusiness;
import com.google.common.collect.Maps;
import com.ceam.biz.activiti.service.IBizBusinessService;
import com.ceam.biz.activiti.service.LeaveService;
import com.ceam.biz.activiti.service.ProcessService;
import com.ceam.core.base.constant.CommonConstants;
import com.ceam.core.base.enums.TaskStatusEnum;
import lombok.AllArgsConstructor;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @description 流程 service
 */
@Service
@AllArgsConstructor
public class ProcessServiceImpl implements ProcessService {

    @Autowired
    private IBizBusinessService bizBusinessService;

    private final RepositoryService repositoryService;
    private final RuntimeService runtimeService;
    private final LeaveService leaveService;

    /**
     * 分页流程列表
     *
     * @param params
     * @return
     */
    @Override
    public IPage<ProcessDto> list(Map<String, Object> params) {
        ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery().latestVersion();
        String name = (String) params.get("name");
        if (StrUtil.isNotBlank(name)) {
            query.processDefinitionNameLike(name);
        }

        String category = MapUtil.getStr(params, "category");
        if (StrUtil.isNotBlank(category)) {
            query.processDefinitionCategory(category);
        }

        int current = MapUtil.getInt(params, CommonConstants.CURRENT);
        int size = MapUtil.getInt(params, CommonConstants.SIZE);

        IPage result = new Page(current, size);
        result.setTotal(query.count());

        List<ProcessDto> deploymentList = query.listPage((current - 1) * size, size)
                .stream()
                .map(processDefinition -> {
                    Deployment deployment = repositoryService.createDeploymentQuery()
                            .deploymentId(processDefinition.getDeploymentId()).singleResult();
                    return ProcessDto.toProcessDto(processDefinition, deployment);
                }).collect(Collectors.toList());
        result.setRecords(deploymentList);
        return result;
    }

    /**
     * 读取xml/image资源
     *
     * @param procInsId
     * @param procDefId
     * @param resType
     * @return
     */
    @Override
    public InputStream readResource(String procInsId, String procDefId, String resType) {

        if (StrUtil.isBlank(procDefId)) {
            ProcessInstance processInstance = runtimeService
                    .createProcessInstanceQuery()
                    .processInstanceId(procInsId)
                    .singleResult();
            procDefId = processInstance.getProcessDefinitionId();
        }
        ProcessDefinition processDefinition = repositoryService
                .createProcessDefinitionQuery()
                .processDefinitionId(procDefId)
                .singleResult();

        String resourceName = "";
        if ("image".equals(resType)) {
            resourceName = processDefinition.getDiagramResourceName();
        } else if ("xml".equals(resType)) {
            resourceName = processDefinition.getResourceName();
        }

        InputStream resourceAsStream = repositoryService
                .getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
        return resourceAsStream;
    }

    /**
     * 根据Key获取最新版本的流程ID，故是唯一的
     * @param defKey
     * @return
     */
    @Override
    public String findProcessDefIdByKey(String defKey) {
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(defKey).latestVersion().singleResult();
        return definition.getId();
    }

    /**
     * 更新状态
     *
     * @param procDefId
     * @param status
     * @return
     */
    @Override
    public Boolean changeStatus(String procDefId, String status) {
        if ("active".equals(status)) {
            repositoryService.activateProcessDefinitionById(procDefId, true, null);
        } else if ("suspend".equals(status)) {
            repositoryService.suspendProcessDefinitionById(procDefId, true, null);
        }
        return Boolean.TRUE;
    }

    /**
     * 删除部署的流程，级联删除流程实例
     *
     * @param deployId
     * @return
     */
    @Override
    public Boolean removeProcIns(String deployId) {
        repositoryService.deleteDeployment(deployId, true);
        return Boolean.TRUE;
    }

    /**
     * 启动请假流程
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean startLeaveProcess(Integer id) {
        // 声明业务载体，用于记录业务申请、启动流程的变量
        BizBusiness business = initBusiness();
        //将数据插入到biz_business表中
        bizBusinessService.insertBizBusiness(business);
        //放入流程变量，键为"duration"，可作为复合判断条件，启动流程
        Map<String, Object> variables = Maps.newHashMap();
        // 这里可以设置各个负责人，key跟模型的代理变量一致
        // variables.put("pm", 1l);
        // variables.put("sup", 1l);
        // variables.put("gm", 1l);
        // variables.put("hr", 1l);
        variables.put("day", 173);
        //传入business，是因为里面含有如流程ID、用户ID等等
        bizBusinessService.startProcess(business, variables);
        return Boolean.TRUE;
    }

    private BizBusiness initBusiness()
    {
        // 声明业务载体，并往载体装载数据
        BizBusiness business = new BizBusiness();
        business.setTableId("1");  //关联表单
        String procDefId = findProcessDefIdByKey("leave");
        business.setProcDefId(procDefId);    //插入流程ID
        business.setTitle("请假");            //插入业务申请标题 -> 请假申请
        business.setProcName("请假申请");      //插入流程名字
        //long userId = getCurrentUserId();               //获取当前用户ID
        business.setUserId(1L);                     //插入用户ID
        // 声明用户载体
        //SysUser user = remoteUserService.selectSysUserByUserId(userId);  //根据用户ID获取用户
        business.setApplyer("CeaM");                         //插入用户名
        business.setStatus(ActivitiConstant.STATUS_DEALING);             //状态处理中(因为这是启动流程时用的，故为处理中)
        business.setResult(ActivitiConstant.RESULT_DEALING);             //结果处理中
        business.setApplyTime(new Date());                               //插入创建时间
        // 返回业务载体
        return business;
    }
}
